package animation;

import com.crunch.math.Matrix33af;

import java.util.HashMap;
import java.util.Map;

/**
 * An character made up from animation resources.
 */
public class Character {
	// initializes the character
	// a single skeleton, animation tree, and animation state machine must be specified
	// all animations used in the animation tree must be specified in the animations map
	public Character(
			Skeleton skeleton,
			AnimationTree animationTree,
			AnimationStateMachine animationStateMachine,
			Map<String, Animation> animations) {
		this.skeleton = skeleton;

		// set up the animation map
		this.animations = new HashMap<String, AnimationInstance>();
		for (Map.Entry<String, Animation> e : animations.entrySet()) {
			// construct animation instance and put it in the map
			AnimationInstance animation = new AnimationInstance(e.getValue(), skeleton);
			this.animations.put(e.getKey(), animation);
		}

		// set up the animation tree
		this.animationTree = new AnimationTreeInstance(animationTree, this.animations);

		// set up the animation state machine
		this.animationStateMachine = new AnimationStateMachineInstance(animationStateMachine, this.animationTree);
	}

	public Skeleton getSkeleton() {
		return skeleton;
	}

	public AnimationTreeInstance getAnimationTree() {
		return animationTree;
	}

	public AnimationStateMachineInstance getAnimationStateMachine() {
		return animationStateMachine;
	}

	public AnimationInstance getAnimation(String name) {
		return animations.get(name);
	}

	private Skeleton skeleton;
	private AnimationTreeInstance animationTree;
	private AnimationStateMachineInstance animationStateMachine;
	private HashMap<String, AnimationInstance> animations;

	////////
	// state

	public State createCharacterState() {
		return new State(this);
	}

	public static class State {
		// private constructor because it must be created by character
		private State(Character character) {
			this.character = character;
			animationStateMachineState = character.animationStateMachine.createState();
			boneMatrices = new Matrix33af[character.getSkeleton().getBoneCount()];
			for (int i = 0; i < boneMatrices.length; ++i) {
				boneMatrices[i] = new Matrix33af();
			}
		}

		public void setVariable(String name, float value) {
			animationStateMachineState.setVariable(name, value);
		}

		public void setVariable(String name, int value) {
			animationStateMachineState.setVariable(name, value);
		}

		public void setStateActive(String name, boolean active) {
			animationStateMachineState.setStateActive(name, active);
		}

		public boolean isStateActive(String name) {
			return animationStateMachineState.isStateActive(name);
		}

		public void triggerEvent(String name) {
			animationStateMachineState.triggerEvent(name);
		}

		// executes active states
		public void update(float dt) {
			animationStateMachineState.update();
			animationStateMachineState.getAnimationTreeState().update(dt);
		}

		public Character getCharacter() {
			return character;
		}

		public AnimationTreeInstance.State getAnimationTreeState() {
			return animationStateMachineState.getAnimationTreeState();
		}

		public AnimationStateMachineInstance.State getAnimationStateMachineState() {
			return animationStateMachineState;
		}

		public Matrix33af[] getBoneMatrices() {
			return boneMatrices;
		}

		private Character character;
		private AnimationStateMachineInstance.State animationStateMachineState;
		private Matrix33af[] boneMatrices;
	}
}
